package com.yelink.metrics.core;

import com.yelink.metrics.core.constant.ModelType;
import com.yelink.metrics.core.constant.annotations.MetricsColumn;
import com.yelink.metrics.core.constant.annotations.MetricsInfo;
import com.yelink.metrics.core.constant.annotations.MetricsUniCode;
import com.yelink.metrics.core.constant.enums.FieldDefine;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author idea
 */
public class MetricsUtils {
    /**
     * 获取类的字段，并保证以下特性
     * <p>1. 父类排在前</p>
     * <p>2. 同一个类能保证顺序</p>
     * <p>3. 如果子类与父类存在相同字段，则只保留子类的</p>
     */
    public static List<Field> getAllInstanceFieldsParentFirst(Class<?> clazz) {
        // 1) 先构造父类优先的层级链
        List<Class<?>> hierarchy = new ArrayList<>();
        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
            // 头插法：父类在前
            hierarchy.add(0, c);
        }

        // 2) 自下而上扫描一次，建立“字段名 -> 首次出现的(最子)类”
        Map<String, Class<?>> keepInClass = new HashMap<>(16);
        // 子类 -> 父类
        for (int i = hierarchy.size() - 1; i >= 0; i--) {
            Class<?> c = hierarchy.get(i);
            for (Field f : c.getDeclaredFields()) {
                if (!Modifier.isStatic(f.getModifiers())) {
                    keepInClass.putIfAbsent(f.getName(), c);
                }
            }
        }

        // 3) 再自上而下真正收集结果
        List<Field> result = new ArrayList<>();
        // 父类 -> 子类
        for (Class<?> c : hierarchy) {
            for (Field f : c.getDeclaredFields()) {
                if (!Modifier.isStatic(f.getModifiers())
                        && keepInClass.get(f.getName()) == c) {
                    // 只在应出现的类加入
                    result.add(f);
                }
            }
        }
        return result;
    }

    public static ModelType resolveModelType(MetricsInfo info) {
        Class<? extends ModelType> enumClass = info.modelEnum();
        String code = info.modelCode();

        if (!enumClass.isEnum()) {
            throw new IllegalArgumentException(enumClass + " is not an enum");
        }

        for (ModelType constant : enumClass.getEnumConstants()) {
            if (Objects.equals(constant.getCode(), code)) {
                return constant;
            }
        }
        throw new IllegalArgumentException("No enum value found for code: " + code + " in " + enumClass.getSimpleName());
    }

    public static boolean checkIsDimension(Field field) {
        MetricsColumn metricsColumn = field.getAnnotation(MetricsColumn.class);
        if(metricsColumn == null) {
            return false;
        }
        return metricsColumn.filedDefine() == FieldDefine.DIMENSION
                || metricsColumn.filedDefine() == FieldDefine.TIME_DIMENSION;
    }
    public static boolean checkIsDimensionDiy(Field field) {
        return field.getAnnotation(MetricsUniCode.class) != null;
    }

}
